package limiter

import (
	"sync"
	"time"
)

const TestPlanCopyMaxTask  = 1
const TestPlanCopyTaskType = "testpalncopy"
const TestPlanCopyTaskCap  = 1
const TaskWaitingStatus = "waiting"
const TaskRunningStatus = "running"
const TaskUser = "user"
const TaskId = "id"
const TaskUsedTime = "usedTime"
const TaskType = "type"
const TaskRecordNumber = "recordNumber"
const TaskStatus = "status"
const TaskWaitingTime = "waitingTime"

var TestPlanTaskInitOnce sync.Once
var testPlanTaskLimiterInstance *testplanTaskLimiter

type testplanTaskLimiter struct {
	taskLimiter
}

func GetTestplanTaskLimiterInstance() *testplanTaskLimiter {
	TestPlanTaskInitOnce.Do(func() {
		testPlanTaskLimiterInstance = new(testplanTaskLimiter)
		testPlanTaskLimiterInstance.createKey()
		testPlanTaskLimiterInstance.lock = new(sync.RWMutex)
		testPlanTaskLimiterInstance.tasks = make(map[string]taskInfo, 0)
	})
	return testPlanTaskLimiterInstance
}

func (this *testplanTaskLimiter) createKey () {
	this.taskRunKey = make(chan int, TestPlanCopyMaxTask)
	for i:=0; i< TestPlanCopyMaxTask; i++ {
		this.taskRunKey <- 1
	}
}

func (this *testplanTaskLimiter) IsLimit () bool {
	this.lock.Lock()
	defer this.lock.Unlock()
	if len(this.tasks) < TestPlanCopyTaskCap {
		return false
	}
	return true
}

func (this *testplanTaskLimiter) StartTask (uuid string, user string, id string, number int) {
	tpInfo := testplanTaskInfo{}
	tpInfo.Type =TestPlanCopyTaskType
	tpInfo.Uuid = uuid
	tpInfo.User = user
	tpInfo.Id = id
	tpInfo.Number = number
	tpInfo.Status = TaskWaitingStatus
	tpInfo.StartWaitingTime = time.Now()
	this.AddTask(tpInfo)

	// 信号量相当与漏桶的水滴， 没有水滴阻塞
	<- this.taskRunKey

	// 开始任务后更新执行状态以及时间状态
	tpInfo.StartTime = time.Now()
	tpInfo.WaitingTime = tpInfo.GetWaitingTime()
	tpInfo.Status = TaskRunningStatus
	this.UpdateTask(uuid, tpInfo)
}

func (this *testplanTaskLimiter) ReleaseTask (uuid string) {
	this.taskRunKey <- 1
	this.DeleteTask(uuid)
}

func (this *testplanTaskLimiter) GetTaskInfo () []map[string]interface{} {
	infos := make([]map[string]interface{}, 0)
	for _, task := range this.tasks {
		taskInfo := make(map[string]interface{}, 0)
		taskInfo[TaskUser] = task.GetUser()
		taskInfo[TaskId] = task.GetId()
		taskInfo[TaskUsedTime] = task.GetUsedTime()
		taskInfo[TaskType] = task.GetType()
		taskInfo[TaskRecordNumber] = task.GetNumber()
		taskInfo[TaskStatus] = task.GetStatus()
		taskInfo[TaskWaitingTime] = task.GetWaitingTime()
		infos = append(infos, taskInfo)
	}
	return infos
}

type testplanTaskInfo struct {
	Type string
	User string
	Uuid string
	Id string
	Number int
	Status string
	StartTime time.Time
	StartWaitingTime time.Time
	UsedTime  time.Duration
	WaitingTime time.Duration
}

func (this testplanTaskInfo) GetType  () string {
	return this.Type
}

func (this testplanTaskInfo) GetUser () string {
	return this.User
}

func (this testplanTaskInfo) GetStartTime  () time.Time {
	return this.StartTime
}

func (this testplanTaskInfo) GetUsedTime () time.Duration {
	if this.Status == TaskWaitingStatus {
		return 0
	}
	return time.Since(this.StartTime)
}

func (this testplanTaskInfo) GetWaitingTime () time.Duration {
	if this.Status == TaskWaitingStatus {
		return time.Since(this.StartWaitingTime)
	}
	return this.WaitingTime
}

func (this testplanTaskInfo) GetUuid () string {
	return this.Uuid
}

func (this testplanTaskInfo) GetId () string {
	return this.Id
}

func (this testplanTaskInfo) GetNumber () int {
	return this.Number
}

func (this testplanTaskInfo) GetStatus () string {
	return this.Status
}






